package com.shr.xsunmvc.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 反射相关方法工具类
 * @author sun haoran
 *
 */
public class ReflectUtil {

	/**
	 * 利用反射调用controller中对应的方法
	 * @param controller controller对象
	 * @param method 方法
	 * @param args method 的参数
	 * @return
	 */
	public static Object invokeMethod(Object controller, Method method, 
			Object... args) {
		try {
			//获取method参数   args 对应的类型
			Class<?>[] paraTypes = method.getParameterTypes() ;
			
			int paraCount = paraTypes == null ? 0 : args.length ;
			
			//参数类型与参数的个数不对应，报异常
			if(paraCount != method.getParameterCount())
				throw new RuntimeException(String.format("Exception in method %s in %s ", 
						method.getName(), controller)) ;
			
			//转换method的参数
			for(int i = 0;i<paraCount;i++){
				args[i] = cast(args[i], paraTypes[i]);
			}
			
			return method.invoke(controller, args);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null ;
	}

	@SuppressWarnings("unchecked")
	private static <T>T cast(Object value, Class<T> clazz) {
		if(value != null && !clazz.isAssignableFrom(value.getClass())){
			if(isType(clazz, int.class, Integer.class))
				value = Integer.parseInt(String.valueOf(value)) ;
			else if(isType(clazz, long.class, Long.class))
				value = Long.parseLong(String.valueOf(value)) ;
			else if(isType(clazz, float.class, Float.class))
				value = Float.parseFloat(String.valueOf(value)) ;
			else if(isType(clazz, double.class, Double.class))
				value = Double.parseDouble(String.valueOf(value));
			else if(isType(clazz, boolean.class, Boolean.class))
				value = Boolean.parseBoolean(String.valueOf(value));
			else if(isType(clazz, String.class))
				value = String.valueOf(value) ;
		}
		return (T) value ;
	}

	private static boolean isType(Object type, Object... isMatchTypes) {
		if (type != null && isMatchTypes != null) {
			for (Object obj : isMatchTypes)
				if (type.equals(obj))
					return true;
		}
		return false;
	}
	
}
